package com.spring.nio.core.event.business;

import com.google.common.collect.Lists;
import com.spring.nio.core.channel.context.SocketChannelContext;
import com.spring.nio.core.event.handler.AbstractEventHandler;
import com.spring.nio.core.event.listener.event.constant.ExceptionEventTypeEnum;
import com.spring.nio.core.event.listener.event.model.NioReadExceptionEventSource;
import com.spring.nio.core.event.model.ChannelCacheDataModel;
import com.spring.nio.core.event.model.EventModel;
import com.spring.nio.core.event.model.EventModelEnum;
import com.spring.nio.core.event.model.FrameData;
import com.spring.nio.core.exception.ExceptionManager;
import com.spring.nio.service.common.Frame;
import com.spring.nio.util.BasicUtil;
import com.spring.nio.util.LocalTime;
import com.spring.nio.util.NioUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;

/**
 * 粘包半包解析器
 *
 * */
@Slf4j
public class StickyHalfBagParseUtil {

    /**
     * 从通道读取数据,此处解决粘包和半包问题, 将cacheDataModel中的数据进行包处理，处理完成后放入eventMode中的completeList中，并清空cacheDataModel处理完成的数据
     * @param eventModel  当前通道就绪的事件模型数据
     * @param channelCacheDataModel 当前通道待处理的缓存数据
     * @param remoteAddress 当前服务端通道对应的远端通道
     * @return
     * */
    public static Boolean parse(EventModel eventModel, ChannelCacheDataModel channelCacheDataModel, String remoteAddress) {
        SelectionKey selectionKey = eventModel.getSelectionKey();
        SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
        SocketChannelContext socketChannelContext = (SocketChannelContext) selectionKey.attachment();

        // 1、读取数据，该缓冲区buffer为accept方法创建的socketChannel在封装为socketChannelContext时为其创建的,所以读取数据也是从通道对应的缓冲区进行读取
        ByteBuffer byteBuffer = socketChannelContext.getByteBuffer();
        int readBytes = 0;
        try {
            while ((readBytes = socketChannel.read(byteBuffer)) > 0 ) {
                // 每读取一次做为一个GroupData进行封装，但是每read一次的大小不一定按照byteBuffer指定大小进行读取
                byteBuffer.flip();
                if (byteBuffer.hasRemaining()) {
                    byte[] bytes = new byte[byteBuffer.remaining()];
                    byteBuffer.get(bytes);

                    // 将当前数据进行封装,每读取一次执行一次处理,处理不了直接进行缓存，按照帧序号缓存之当前socketChannel对应的ChannelCacheDataModel对象中
                    FrameData frameData = new FrameData();
                    frameData.setLength(bytes.length);
                    frameData.setIndex(channelCacheDataModel.getIndex());
                    frameData.setBytes(bytes);
                    frameData.setStatus("UN_HANDLE");
                    channelCacheDataModel.setIndex(frameData.getIndex() + 1);

                    // 验证及处理当前帧
                    int result = verificateHandleCurrentGroupData(channelCacheDataModel, frameData, eventModel);
                    if(result == -2) {
                        throw new RuntimeException("通道 [" + socketChannelContext.getRemoteAddress() + "] 解析当前帧 [序号 = " + frameData.getIndex() + "] 的帧总长度数据错误");
                    }

                    if(result == -3) {
                        throw new RuntimeException("通道 [" + socketChannelContext.getRemoteAddress() + "] 解析当前帧 [序号 = " + frameData.getIndex() + "] 发生未知错误");
                    }

                    byteBuffer.clear();
                }
            }

            /**
             * readBytes 读取到-1: 此种情况仅会出现在普通请求操作以及文件上传请求操作:
             *  1、普通请求读取到-1，则直接关闭socket连接,文件上传读取到-1;
             *  2、文件客户端上传: 此时读取到-1, 同时也主动关闭对应的通道
             * */
            if(readBytes == -1) {
                // 释放当前通道所占用资源
                AbstractEventHandler.clearChannelCache(remoteAddress);
                eventModel.getSelectionKey().cancel();
                NioUtil.closedAndRelease(socketChannelContext, true, true, true);
                return Boolean.FALSE;
            }
        } catch (Exception e) {
            closeChannelHandle(e, eventModel, socketChannelContext);
            // 一旦读取当前通道产生异常，则取消当前通道注册的读事件
            eventModel.getSelectionKey().cancel();
            return Boolean.FALSE;
        } finally {
            byteBuffer.clear();
        }

        // 2、判断当前数据能否处理，能达到多少处理标准就处理多少数据
        if(judgeIsCouldExecuteHandle(eventModel, channelCacheDataModel)) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }

    /**
     * 读事件异常处理
     * @param e
     * @param eventModel
     * @param socketChannelContext
     * */
    private static void closeChannelHandle(Exception e, EventModel eventModel, SocketChannelContext socketChannelContext) {
        NioReadExceptionEventSource nioReadExceptionEventSource = new NioReadExceptionEventSource();
        nioReadExceptionEventSource.setSocketChannelContext(socketChannelContext);
        nioReadExceptionEventSource.setModule("ReadEventHandler --> method [readData] --> 产生异常");
        nioReadExceptionEventSource.setException(e);
        nioReadExceptionEventSource.setExceptionEventTypeEnum(ExceptionEventTypeEnum.NIO_READ_EVENT_HANDLER);
        nioReadExceptionEventSource.setIsSend(Boolean.FALSE);
        nioReadExceptionEventSource.setIsLogout(eventModel.getEventModelEnum().equals(EventModelEnum.CHAT_EVENT_ACCEPTOR));

        if(nioReadExceptionEventSource.getIsLogout()) {
            // 如果为用户断开连接接收到-1，那么isLogout必为true,此时，需要清除所有上传或下载任务
            nioReadExceptionEventSource.setIsClearSingleFileUploadTask(Boolean.TRUE);
            nioReadExceptionEventSource.setIsClearSingleFileDownloadTask(Boolean.TRUE);
        } else {
            // 当前通道产生异常非主通道，则根据当前读事件的模型枚举选择清除对应的文件上传或是下载任务
            nioReadExceptionEventSource.setIsClearSingleFileUploadTask(eventModel.getEventModelEnum().getName().equals(EventModelEnum.FILE_UPLOAD_EVENT_ACCEPTOR.getName()));
            nioReadExceptionEventSource.setIsClearSingleFileDownloadTask(eventModel.getEventModelEnum().getName().equals(EventModelEnum.FILE_DOWNLOAD_EVENT_ACCEPTOR.getName()));
        }

        ExceptionManager.handleException(nioReadExceptionEventSource);
    }

    /**
     * 验证及处理当前帧
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param currentFrameData 当前通道待处理缓存数据
     * @param currentEventModel 当前通道事件数据模型
     *      基本位数据: 4 + 1 + 4 + 3 + [动态大小] = 12 + [动态大小]
     *          帧组成: 4B : 当前帧总长度
     *                 1B : 当前帧是否是结束帧
     *                 4B : 当前帧发送序号(由客户端确定)
     *                 3B : 帧基本数据 [1B : 帧类型, 1B : 文件类型, 1B : 文件操作类型]
     *            动态大小 : [4B + 不确定大小]，其中4B为动态数据长度大小(int 4字节)
     */
    private static int verificateHandleCurrentGroupData(ChannelCacheDataModel currentChannelCacheDataModel, FrameData currentFrameData, EventModel currentEventModel) {
        // 1、判断当前数据长度是否能够处理，即校验基本位字节段 int orginStreamDataIndex = 4 + 1 + 4 + 3 + sendDataLengthBytes.Length + sendDataBytes.Length;
        if(!CollectionUtils.isEmpty(currentChannelCacheDataModel.getChannelCacheDataList())) {
            List<FrameData> cacheList = currentChannelCacheDataModel.getChannelCacheDataList();
            // 先将新读入的数据追加至当前通道缓存对象数据集合末尾
            cacheList.add(currentFrameData);
            // 当前通道缓存数据排序(升序排序)，保证处理顺序的按照读入的顺序
            cacheList.stream().sorted(Comparator.comparing(FrameData::getIndex));

            // 1.1、处理缓存集合中的数据
            int currentIndex = 0;
            while (currentIndex < cacheList.size()) {
                currentIndex = executeParseCurrentGroupData(currentChannelCacheDataModel, cacheList.get(currentIndex), currentIndex, currentEventModel);

                // 返回 -1 或 cacheList缓存越界，直接返回，执行下一次socketChannel.read()读取
                if(currentIndex == -1 || (currentIndex >= cacheList.size())) {
                    return -1;
                }

                // 判断当前索引[currentIndex]指示的GroupData是否处于处理完成状态，如果是则索引自增1，开始处理下一份GourpData，如果不是则当前索引无需自增1，直接当前索引继续处理
                // 备注：不是UN_HANDLE状态，表示当前索引对应的GroupData发生了粘包，一部分数据为上一帧的数据，一部分为下一帧的数据，所以需要继续处理
                FrameData nextIndexFrameData = cacheList.get(currentIndex);
                if(StringUtils.equals(nextIndexFrameData.getStatus(), "UN_HANDLE")) {
                    // 处理前判断帧的长度是否小于16B，小于16表示帧的字节长度不够处理需要重新读取那么此时返回-1，如果大于16B则直接处理
                    Boolean result = frameSumLengthSmallerThan16(currentChannelCacheDataModel, nextIndexFrameData, currentIndex);
                    if(!result) {
                        // 将小于16的当前帧复制到下一帧失败，说明没有下一帧，需要重新开启socketChannel.read()读取，此时直接返回
                        return -1;
                    }

                    // 此处已经将小于16个字节的基础数据拷贝至下一个GroupData，并移除了小于16的帧对应GroupData, 那么索引无需变化，直接当前索引对应的GroupData进行处理
                    continue;
                }

                // 如果没有剩余，说明刚好加上 [currentIndex] 指定的GroupData所有数据刚好等于currentFrameSumLength，那么直接自增1，执行下一次处理
                currentIndex++;
            }

            // 都不符合，则返回-3，位置错误，关闭当前SocketChannel，如果是文件服务，还需关闭文件对应的通道
            return -3;
        } else {
            // 1、追加数据
            currentChannelCacheDataModel.getChannelCacheDataList().add(currentFrameData);

            // 2、当前帧GroupData字节长度直接小于16，则追加进缓存队列，返回-1，执行下次socketChannel.read()读取完成后重新处理
            if(currentFrameData.getLength() < 16) {
                return -1;
            }

            // 3、大于16则直接处理
            return executeParseCurrentGroupData(currentChannelCacheDataModel, currentFrameData, 0, currentEventModel);
        }
    }

    /**
     * 处理当前帧数据长度小于16
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param nextIndexFrameData 当前通道待处理缓存数据
     * @param currentIndex 当前groupData对应在通道缓存对象中的索引
     * @return
     */
    private static Boolean frameSumLengthSmallerThan16(ChannelCacheDataModel currentChannelCacheDataModel, FrameData nextIndexFrameData, int currentIndex) {
        // 获取下一个GroupData
        if((currentIndex + 1) >= currentChannelCacheDataModel.getChannelCacheDataList().size()) {
            return Boolean.FALSE;
        }

       FrameData nextIndex2GroupData = currentChannelCacheDataModel.getChannelCacheDataList().get(currentIndex + 1);
        byte[] newBytes = new byte[nextIndexFrameData.getLength() + nextIndex2GroupData.getLength()];
        System.arraycopy(nextIndexFrameData.getBytes(), 0, newBytes, 0, nextIndexFrameData.getLength());
        System.arraycopy(nextIndex2GroupData.getBytes(), 0, newBytes, nextIndexFrameData.getLength(), nextIndex2GroupData.getLength());
        nextIndex2GroupData.setLength(newBytes.length);
        nextIndex2GroupData.setBytes(newBytes);
        nextIndex2GroupData.setStatus("UN_HANDLE");

        // 移除被复制到下一个帧的当前帧
        currentChannelCacheDataModel.getChannelCacheDataList().remove(nextIndexFrameData);
        return Boolean.TRUE;
    }

    /**
     * 处理当前数据，此时当前帧数据最应该大于16，但是存在首次socketChannel.read()读取直接就小于16，那么需要执行一次小于16的特殊处理
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param currentGroupData 当前通道待处理缓存数据
     * @param currentIndex 当前groupData对应在通道缓存对象中的索引
     * @param currentEventModel 当前通道事件数据模型
     */
    private static int executeParseCurrentGroupData(ChannelCacheDataModel currentChannelCacheDataModel, FrameData currentGroupData, int currentIndex, EventModel currentEventModel) {
        int currentGroupDataLength = currentGroupData.getLength();
        // 1、判断当前帧长度是否小于16，如果小于16需要将当前帧字节数据复制到下一个字节
        if(currentGroupData.getLength() < 16) {
            Boolean result = frameSumLengthSmallerThan16(currentChannelCacheDataModel, currentGroupData, currentIndex);
            if(!result) {
                // 将小于16的当前帧复制到下一帧失败，说明没有下一帧，需要重新开启socketChannel.read()读取，此时直接返回
                return -1;
            }
            // 此处已经将小于16个字节的基础数据拷贝至下一个GroupData，并移除了小于16的帧对应GroupData, 那么索引无需变化，直接当前索引对应的GroupData进行处理
            return currentIndex;
        }

        // 2、解析当前帧总长度4B
        int currentFrameSumLength = parseFrameSumLength(currentGroupData);
        if(currentFrameSumLength <= 0) {
            log.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ReadEventHandler | --> 通道 [{}] 解析当前帧 [序号 = {}] 的帧总长度数据错误, 解析出来的帧总长度 = [{}]",
                    currentEventModel.getRemoteAddress(), currentGroupData.getIndex(), currentFrameSumLength);
            // 帧总长度解析错误，返回-2，关闭当前SocketChannel通道，如果存在文件通道还需关闭文件通道
            return -2;
        }

        // 3、如果当前帧指定的总长度(currentFrameSumLength) = 当前帧缓存数据长度  -->  刚好能够处理完整帧
        if(currentFrameSumLength == currentGroupDataLength) {
            addCompleteFrameData(currentChannelCacheDataModel, currentGroupData, currentIndex, currentFrameSumLength, currentEventModel);
            return currentIndex;
        }

        // 4、如果当前帧指定的总长度(currentFrameSumLength) > 当前帧缓存数据长度  -->  完整帧的数据需要跨越多个groupData
        if(currentFrameSumLength > currentGroupDataLength) {
            return parseFrameSumLengthBiggerThanCurrentGroupDataLength(currentChannelCacheDataModel, currentGroupData, currentIndex, currentFrameSumLength, currentEventModel);
        }

        // 5、如果当前帧指定的总长度(currentFrameSumLength) > 当前帧缓存数据长度  -->  完整帧在当前帧中处理完还存在剩余
        if(currentFrameSumLength < currentGroupDataLength) {
            return parseFrameSumLengthSmallerThanCurrentGroupDataLength(currentChannelCacheDataModel, currentGroupData, currentIndex, currentFrameSumLength, currentEventModel);
        }

        // 都不符合，则返回-3，位置错误，关闭当前SocketChannel，如果是文件服务，还需关闭文件对应的通道
        return -3;
    }

    /**
     * 当前帧总长度数据大于当前通道缓存数据处理逻辑
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param currentFrameData 当前通道待处理缓存数据
     * @param currentIndex 当前groupData对应在通道缓存对象中的索引
     * @param currentFrameSumLength 当前通道待处理缓存数据解析出的帧总长度
     * @param currentEventModel 当前通道事件数据模型
     */
    private static int parseFrameSumLengthBiggerThanCurrentGroupDataLength(ChannelCacheDataModel currentChannelCacheDataModel,
        FrameData currentFrameData, int currentIndex, int currentFrameSumLength, EventModel currentEventModel) {
        // 1、先处理当前通道数据，构建新的
        FrameData newCompleteFrameData = new FrameData();
        byte[] newCompleteGroupBytes = new byte[currentFrameSumLength - 4];
        System.arraycopy(currentFrameData.getBytes(), 4, newCompleteGroupBytes, 0, (currentFrameData.getLength() - 4));
        newCompleteFrameData.setLength(currentFrameData.getLength() - 4);
        newCompleteFrameData.setEndFrame(newCompleteGroupBytes[0]);
        byte[] indexBytes = new byte[4];
        indexBytes[0] = newCompleteGroupBytes[1];
        indexBytes[1] = newCompleteGroupBytes[2];
        indexBytes[2] = newCompleteGroupBytes[3];
        indexBytes[3] = newCompleteGroupBytes[4];
        newCompleteFrameData.setIndex(BasicUtil.byteArrayToInt(indexBytes));

        // 2、提前从当前通道缓存中根据当前索引获取下一份数据
        int nextIndex = currentIndex + 1;
        FrameData nextFrameData = null;
        while (true) {
            // 3、下一个帧缓存数据索引,并判断下一帧缓存数据是否存在，不存在则不处理
            if(nextIndex >= currentChannelCacheDataModel.getChannelCacheDataList().size()) {
                // 此处如果循环过程出现索引越界，那说明当前帧都没有处理完，虽说跨过几帧，但是都是白处理的，所以此处还是需要将当前处理的GroupData设置为未处理后返回
                currentChannelCacheDataModel.getChannelCacheDataList().stream().forEach(groupData -> groupData.setStatus("UN_HANDLE"));
                return nextIndex;
            }

            nextFrameData = currentChannelCacheDataModel.getChannelCacheDataList().get(nextIndex);
            int nextGroupDataLenth = nextFrameData.getLength();
            if((nextGroupDataLenth + newCompleteFrameData.getLength()) == (currentFrameSumLength - 4)) {
                System.arraycopy(nextFrameData.getBytes(), 0, newCompleteGroupBytes, newCompleteFrameData.getLength(), nextGroupDataLenth);
                newCompleteFrameData.setLength(newCompleteFrameData.getLength() + nextGroupDataLenth);
                newCompleteFrameData.setBytes(newCompleteGroupBytes);
                nextFrameData.setStatus("HANDLE_SUCCESS");
                currentEventModel.getFullFrameDataList().add(newCompleteFrameData);

                // 处理完当前帧，移除已经为HANDLE_SUCCESS状态的数据包
                currentFrameData.setStatus("HANDLE_SUCCESS");
                List<FrameData> removeList = Lists.newArrayList();
                for(int i = 0; (i <= nextIndex && i < currentChannelCacheDataModel.getChannelCacheDataList().size()); i++) {
                    if("HANDLE_SUCCESS".equals(currentChannelCacheDataModel.getChannelCacheDataList().get(i).getStatus())) {
                        removeList.add(currentChannelCacheDataModel.getChannelCacheDataList().get(i));
                    }
                }
                currentChannelCacheDataModel.getChannelCacheDataList().removeAll(removeList);
                break;
            }

            // 4、说明当前索引对应的帧数据存在跨越，即下一帧依旧未能获取到完整帧，需要再次循环
            if((nextGroupDataLenth + newCompleteFrameData.getLength()) < (currentFrameSumLength - 4)) {
                System.arraycopy(nextFrameData.getBytes(), 0, newCompleteGroupBytes, newCompleteFrameData.getLength(), nextFrameData.getLength());
                newCompleteFrameData.setLength(newCompleteFrameData.getLength() + nextGroupDataLenth);
                nextFrameData.setStatus("HANDLE_SUCCESS");
                nextIndex = nextIndex + 1;
                continue;
            }

            // 5、说明当前索引对应的帧数据存在跨越，一部分是上一帧，一部分是下一帧
            if((nextGroupDataLenth + newCompleteFrameData.getLength()) > (currentFrameSumLength - 4)) {
                // 5.1、处理上一帧剩余数据，此处已经处理完,restNeedReadBytesCount的计算会导致数组越界异常，必须控制好，需要减去帧总长度两个字节
                int restNeedReadBytesCount = (currentFrameSumLength - 4)  - newCompleteFrameData.getLength();
                System.arraycopy(nextFrameData.getBytes(), 0, newCompleteGroupBytes, newCompleteFrameData.getLength(), restNeedReadBytesCount);
                newCompleteFrameData.setLength(newCompleteFrameData.getLength() + restNeedReadBytesCount);
                newCompleteFrameData.setBytes(newCompleteGroupBytes);
                currentEventModel.getFullFrameDataList().add(newCompleteFrameData);

                // 5.2、处理当前帧缓存数据剩余字节,即变为新的缓存字节数组
                byte[] restBytes = new byte[nextGroupDataLenth - restNeedReadBytesCount];
                System.arraycopy(nextFrameData.getBytes(), restNeedReadBytesCount, restBytes, 0, restBytes.length);
                nextFrameData.setLength(restBytes.length);
                nextFrameData.setBytes(restBytes);
                nextFrameData.setStatus("UN_HANDLE");

                // 5.3、处理完当前帧，移除已经为HANDLE_SUCCESS状态的数据包
                currentFrameData.setStatus("HANDLE_SUCCESS");
                List<FrameData> removeList = Lists.newArrayList();
                for(int i = 0; (i < nextIndex && i < currentChannelCacheDataModel.getChannelCacheDataList().size()); i++) {
                    if("HANDLE_SUCCESS".equals(currentChannelCacheDataModel.getChannelCacheDataList().get(i).getStatus())) {
                        removeList.add(currentChannelCacheDataModel.getChannelCacheDataList().get(i));
                    }
                }
                currentChannelCacheDataModel.getChannelCacheDataList().removeAll(removeList);

                // 5.4、下一帧处理完时，需要判断下一帧长度是否小于16，小于16需要继续复制到下一帧
                Boolean result = frameSumLengthSmallerThan16(currentChannelCacheDataModel, nextFrameData, nextIndex);
                if(!result) {
                    // 将小于16的当前帧复制到下一帧失败，说明没有下一帧，需要重新开启socketChannel.read()读取，此时直接返回
                    return -1;
                }
                break;
            }
        }
        return nextIndex;
    }

    /**
     * 当前帧总长度数据小于当前通道缓存数据处理逻辑
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param currentFrameData 当前通道待处理缓存数据
     * @param currentIndex 当前groupData对应在通道缓存对象中的索引
     * @param currentFrameSumLength 当前通道待处理缓存数据解析出的帧总长度
     * @param currentEventModel 当前通道事件数据模型
     */
    private static int parseFrameSumLengthSmallerThanCurrentGroupDataLength(ChannelCacheDataModel currentChannelCacheDataModel,
        FrameData currentFrameData, int currentIndex, int currentFrameSumLength, EventModel currentEventModel) {
        // 1、处理当前GroupData属于上一帧的数据
        FrameData newCompleteGroupData = new FrameData();
        byte[] newCompleteGroupBytes = new byte[currentFrameSumLength - 4];
        System.arraycopy(currentFrameData.getBytes(), 4, newCompleteGroupBytes, 0, newCompleteGroupBytes.length);
        newCompleteGroupData.setLength(newCompleteGroupBytes.length);
        newCompleteGroupData.setEndFrame(newCompleteGroupBytes[0]);
        byte[] indexBytes = new byte[4];
        indexBytes[0] = newCompleteGroupBytes[1];
        indexBytes[1] = newCompleteGroupBytes[2];
        indexBytes[2] = newCompleteGroupBytes[3];
        indexBytes[3] = newCompleteGroupBytes[4];
        newCompleteGroupData.setIndex(BasicUtil.byteArrayToInt(indexBytes));
        currentEventModel.getFullFrameDataList().add(newCompleteGroupData);

        // 2、处理当前GroupData属于下一帧的数据，即移除上一帧的字节数据，只保留属于下一帧的字节数据，同时当前GroupData依旧是未处理状态[UN_HANDLE]
        byte[] restBytes = new byte[currentFrameData.getLength() - (4 + newCompleteGroupBytes.length)];
        System.arraycopy(currentFrameData.getBytes(), (4 + newCompleteGroupBytes.length), restBytes, 0, restBytes.length);
        currentFrameData.setLength(restBytes.length);
        currentFrameData.setBytes(restBytes);
        currentFrameData.setStatus("UN_HANDLE");

        // 3、处理完当前帧，移除索引小于 [currentIndex] 之前已经为HANDLE_SUCCESS状态的数据包
        List<FrameData> removeList = Lists.newArrayList();
        for(int i = 0; (i < currentIndex && i < currentChannelCacheDataModel.getChannelCacheDataList().size()); i++) {
            if("HANDLE_SUCCESS".equals(currentChannelCacheDataModel.getChannelCacheDataList().get(i).getStatus())) {
                removeList.add(currentChannelCacheDataModel.getChannelCacheDataList().get(i));
            }
        }
        currentChannelCacheDataModel.getChannelCacheDataList().removeAll(removeList);

        // 4、下一帧处理完时，需要判断下一帧长度是否小于16，小于16需要继续复制到下一帧
        Boolean result = frameSumLengthSmallerThan16(currentChannelCacheDataModel, currentFrameData, currentIndex);
        if(!result) {
            // 将小于16的当前帧复制到下一帧失败，说明没有下一帧，需要重新开启socketChannel.read()读取，此时直接返回
            return -1;
        }
        return currentIndex;
    }

    /**
     * 添加完整待处理帧数据
     * @param currentChannelCacheDataModel 当前通道缓存对象
     * @param currentFrameData 当前通道新读入缓存数据
     * @param currentIndex 当前groupData对应在通道缓存对象中的索引
     * @param currentFrameSumLength 当前帧解析后指定的总长度
     * @param currentEventModel 当前通道事件数据模型
     */
    private static void addCompleteFrameData(ChannelCacheDataModel currentChannelCacheDataModel, FrameData currentFrameData, int currentIndex, int currentFrameSumLength, EventModel currentEventModel) {
        // 1、移除当前帧缓存数据中的帧总长度数据添加至新的byte数据
        byte[] newCompleteBytesData = new byte[currentFrameSumLength - 4];
        System.arraycopy(currentFrameData.getBytes(), 4, newCompleteBytesData, 0, (currentFrameSumLength - 4));
        FrameData newCompleteFrameData = new FrameData();
        newCompleteFrameData.setBytes(newCompleteBytesData);
        newCompleteFrameData.setLength(newCompleteBytesData.length);
        // 设置结束帧标记
        newCompleteFrameData.setEndFrame(newCompleteBytesData[0]);
        // 序号采用客户端发送过来的帧数据进行设置 1~4
        byte[] indexBytes = new byte[4];
        indexBytes[0] = newCompleteBytesData[1];indexBytes[1] = newCompleteBytesData[2];indexBytes[2] = newCompleteBytesData[3];indexBytes[3] = newCompleteBytesData[4];
        newCompleteFrameData.setIndex(BasicUtil.byteArrayToInt(indexBytes));
        currentEventModel.getFullFrameDataList().add(newCompleteFrameData);
        currentFrameData.setStatus("HANDLE_SUCCESS");

        List<FrameData> removeList = Lists.newArrayList();
        for(int i = 0; (i <= currentIndex && i < currentChannelCacheDataModel.getChannelCacheDataList().size()); i++) {
            if(i <= currentIndex && "HANDLE_SUCCESS".equals(currentChannelCacheDataModel.getChannelCacheDataList().get(i).getStatus())) {
                removeList.add(currentChannelCacheDataModel.getChannelCacheDataList().get(i));
            }
        }
        currentChannelCacheDataModel.getChannelCacheDataList().removeAll(removeList);
    }

    /**
     * 判断当前通道内容是否能够进行业务处理，不能处理直接返回，直到能够进行业务处理
     * @param eventModel 当前通道事件数据模型
     * @param channelCacheDataModel 当前通道缓存数据
     * @return 是否能够进行后续处理
     */
    private static Boolean judgeIsCouldExecuteHandle(EventModel eventModel, ChannelCacheDataModel channelCacheDataModel) {
        // 1、移除通道中成功处理的数据
        channelCacheDataModel.getChannelCacheDataList().removeIf(groupData -> groupData.getStatus().equals("HANDLE_SUCCESS"));

        // 2、移除掉数据状态为[HANDLE_SUCCESS] 成功，由于channelCacheDataModel中的list数据是连续增长的GroupData，且处理成功[HANDLE_SUCCESS]状态的数据永远排在list最前面，所以移除掉后剩余未处理的数据的索引已经为从1开始，此处需要重置
        channelCacheDataModel.setIndex(1);
        // 3、如果有未成功处理的缓存数据，将剩余无法参与处理的数据重新计算帧索引值，之后再次通过SocketChannel读取时，继续往channelCacheDataModel.getList()后追加
        if(!CollectionUtils.isEmpty(channelCacheDataModel.getChannelCacheDataList())) {
            for(FrameData groupData : channelCacheDataModel.getChannelCacheDataList()) {
                groupData.setIndex(channelCacheDataModel.getIndex());
                channelCacheDataModel.setIndex(groupData.getIndex() + 1);
            }

            /*log.info("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ReadEventHandler | --> 当前通道 [{}] 数据处理部分成功，存在未处理成功的帧数据，个数为 [{}], 未成功处理的数据将会在下次读取时处理", currentAddress, channelCacheDataModel.getList().size());*/
        }

        // 3、在半包和拆包处理中已经可以完整处理的帧数据移至当前事件对象eventModel对应的completeList中
        if(CollectionUtils.isEmpty(eventModel.getFullFrameDataList())) {
            //log.warn("[ " + LocalTime.formatDate(LocalDateTime.now()) + " ] ReadEventHandler | --> 当前通道 [{}] 待进行数据字节解析处理集合为空", currentAddress);
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    /**
     * 读取当前帧总长度
     * @return 返回当前帧总长度
     */
    private static int parseFrameSumLength(FrameData currentGroupData) {
        byte[] indexBytes = new byte[4];
        indexBytes[0] = currentGroupData.getBytes()[0];
        indexBytes[1] = currentGroupData.getBytes()[1];
        indexBytes[2] = currentGroupData.getBytes()[2];
        indexBytes[3] = currentGroupData.getBytes()[3];
        return BasicUtil.byteArrayToInt(indexBytes);
    }
}
